cmake_minimum_required(VERSION 3.14.0)

include_guard(GLOBAL)

include(${CMAKE_SOURCE_DIR}/cmake/component.cmake)

function(cc_setup)
  if(NOT CC_SETUP_DONE)
    set(CMAKE_CXX_STANDARD 17 PARENT_SCOPE)
    set(CMAKE_CXX_STANDARD_REQUIRED True PARENT_SCOPE)

    set(COMPILE_OPTION_DEBUG -Werror -Wall -Wextra -Wno-unused-parameter -Wno-missing-field-initializers)
    set(COMPILE_OPTION_RELEASE -O3 -march=native)
    add_compile_options("$<$<CONFIG:Debug>:${COMPILE_OPTION_DEBUG}>")
    add_compile_options("$<$<CONFIG:Release>:${COMPILE_OPTION_RELEASE}>")
    add_link_options(-Wl,-rpath,. -static-libgcc -static-libstdc++ -pthread -ldl)

    set(CC_SETUP_DONE 1 PARENT_SCOPE)
  endif()
endfunction()

function(cc_library)
  if(NOT NS)
    message(FATAL_ERROR "Undefined NS!")
  endif()
  if(${ARGC} GREATER_EQUAL 2)
    set(REPO_SRC_DIR ${ARGV1})
    set(REPO_INC_DIR ${ARGV0})
  elseif(${ARGC} EQUAL 1)
    if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/src)
      set(REPO_SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src)
    else()
      unset(REPO_SRC_DIR)
    endif()
    set(REPO_INC_DIR ${ARGV0})
  else()
    if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/src)
      set(REPO_SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src)
    else()
      unset(REPO_SRC_DIR)
    endif()
    if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/inc)
      set(REPO_INC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/inc)
      configure_file(${CMAKE_SOURCE_DIR}/cmake/in/component.h.in ${REPO_INC_DIR}/component.h @ONLY)
    else()
      unset(REPO_INC_DIR)
    endif()
  endif()
  cc_setup()

  if(REPO_INC_DIR)
    set(INC_DIR ${PROJECT_BINARY_DIR}/inc)
    file(RELATIVE_PATH PROJ_REL_PATH ${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR})
    set(INC_SRC_DIR ${INC_DIR}/${PROJ_REL_PATH})
    if (${CMAKE_VERSION} VERSION_LESS "3.20.0")
      get_filename_component(INC_PARENT_DIR ${INC_SRC_DIR} DIRECTORY)
    else()
      cmake_path(GET INC_SRC_DIR PARENT_PATH INC_PARENT_DIR)
    endif()
    file(MAKE_DIRECTORY ${INC_PARENT_DIR})
    file(CREATE_LINK ${REPO_INC_DIR}/ ${INC_SRC_DIR} SYMBOLIC)
  endif()

  if(REPO_SRC_DIR)
    file(GLOB_RECURSE SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${REPO_SRC_DIR}/*.cc ${REPO_SRC_DIR}/*.cpp)
    add_library(${NS}__${PROJECT_NAME}__cc_lib ${SOURCES})
      set_target_properties(${NS}__${PROJECT_NAME}__cc_lib PROPERTIES OUTPUT_NAME ${PROJECT_NAME})
      set_target_properties(${NS}__${PROJECT_NAME}__cc_lib PROPERTIES OUTPUT_NAME_DEBUG ${PROJECT_NAME}_d)
      if(INC_DIR)
        target_include_directories(${NS}__${PROJECT_NAME}__cc_lib PUBLIC ${INC_DIR}/)
      endif()
      if(DOWNLOAD_DIR)
        add_dependencies(${NS}__${PROJECT_NAME}__cc_lib ${NS}__${PROJECT_NAME}__repo)
      endif()
  elseif(INC_DIR)
    add_library(${NS}__${PROJECT_NAME}__cc_lib INTERFACE)
      target_include_directories(${NS}__${PROJECT_NAME}__cc_lib INTERFACE ${INC_DIR}/)
      if(DOWNLOAD_DIR)
        add_dependencies(${NS}__${PROJECT_NAME}__cc_lib ${NS}__${PROJECT_NAME}__repo)
      endif()
    set(${NS}__${PROJECT_NAME}__cc_lib__is_interface 1 PARENT_SCOPE)
  else()
    add_library(${NS}__${PROJECT_NAME}__cc_lib INTERFACE)
    set(${NS}__${PROJECT_NAME}__cc_lib__is_interface 1 PARENT_SCOPE)
  endif()
endfunction()

function(cc_import)
  message(FATAL_ERROR "Not implemented!") # Todo
endfunction()

function(cc_test)
  if(NOT NS)
    message(FATAL_ERROR "Undefined NS!")
  endif()
  if(${ARGC} EQUAL 1)
    set(REPO_TEST_SRC_DIR ${ARGV0})
  else()
    if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/test/src)
      set(REPO_TEST_SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/test/src)
    else()
      unset(REPO_TEST_SRC_DIR)
    endif()
  endif()
  cc_setup()

  if(REPO_TEST_SRC_DIR)
    file(GLOB_RECURSE SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${REPO_TEST_SRC_DIR}/*.cc ${REPO_TEST_SRC_DIR}/*.cpp)
    add_executable(${NS}__${PROJECT_NAME}__cc_test ${SOURCES})
      set_target_properties(${NS}__${PROJECT_NAME}__cc_test PROPERTIES OUTPUT_NAME ${PROJECT_NAME}__cc_test)
      set_target_properties(${NS}__${PROJECT_NAME}__cc_test PROPERTIES OUTPUT_NAME_DEBUG ${PROJECT_NAME}__cc_test_d)
      target_link_libraries(${NS}__${PROJECT_NAME}__cc_test PRIVATE ${NS}__${PROJECT_NAME}__cc_lib)
  else()
    message(FATAL_ERROR "Missing test/src for ${NS}__${PROJECT_NAME}__cc_test!")
  endif()
endfunction()

function(cc_binary)
  set(NS application)
  if(${ARGC} EQUAL 1)
    set(REPO_SRC_DIR ${ARGV0})
  else()
    if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/src)
      set(REPO_SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src)
    else()
      unset(REPO_SRC_DIR)
    endif()
  endif()
  cc_setup()

  if(REPO_SRC_DIR)
    file(GLOB_RECURSE SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${REPO_SRC_DIR}/*.cc ${REPO_SRC_DIR}/*.cpp)
    add_executable(${NS}__${PROJECT_NAME}__cc_bin ${SOURCES})
      set_target_properties(${NS}__${PROJECT_NAME}__cc_bin PROPERTIES OUTPUT_NAME ${PROJECT_NAME}__cc_bin)
      set_target_properties(${NS}__${PROJECT_NAME}__cc_bin PROPERTIES OUTPUT_NAME_DEBUG ${PROJECT_NAME}__cc_bin_d)
  else()
    message(FATAL_ERROR "Missing src for ${NS}__${PROJECT_NAME}__cc_bin!")
  endif()
endfunction()
